﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Fonour.Domain;
using Fonour.Domain.IRespositories;
using Microsoft.EntityFrameworkCore;

namespace Fonour.EntityFrameworkCore.Repositories
{
    public abstract class FonourRepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
        where TEntity : Entity<TPrimaryKey>
    {
        private readonly FonourDbContext _dbContext;

        public FonourRepositoryBase(FonourDbContext dbContext)
        {
            _dbContext = dbContext;
        }
        public List<TEntity> GetAllList()
        {
            return _dbContext.Set<TEntity>().ToList();
        }

        public List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate)
        {
            return _dbContext.Set<TEntity>().Where(predicate).ToList();
        }

        public TEntity Get(TPrimaryKey id)
        {
            return _dbContext.Set<TEntity>().FirstOrDefault(CreateEqualityExpressionForId(id));
        }

        public TEntity FirseOrDefault(Expression<Func<TEntity, bool>> predicate)
        {
            return _dbContext.Set<TEntity>().FirstOrDefault(predicate);
        }

        public TEntity Insert(TEntity entity)
        {
            _dbContext.Set<TEntity>().Add(entity);
            return entity;
        }

        public TEntity Update(TEntity entity)
        {
            _dbContext.Set<TEntity>().Attach(entity);
            _dbContext.Entry(entity).State = EntityState.Modified;
            return entity;
        }

        public TEntity InsertOrUpdate(TEntity entity)
        {
            if (Get(entity.Id) != null)
                return Update(entity);
            return Insert(entity);
        }

        public void Delete(TEntity entity)
        {
            _dbContext.Set<TEntity>().Remove(entity);
        }

        public void Delete(TPrimaryKey id)
        {
            _dbContext.Set<TEntity>().Remove(Get(id));
        }

        public void Delete(Expression<Func<TEntity, bool>> @where, bool autoSave = true)
        {
            _dbContext.Set<TEntity>().Where(where).ToList().ForEach(it => _dbContext.Set<TEntity>().Remove(it));
        }

        public IQueryable<TEntity> LoadPageList(int startPage, int pageSize, out int rowCount, Expression<Func<TEntity, bool>> @where, Expression<Func<TEntity, object>> order)
        {
            var result = from p in _dbContext.Set<TEntity>() select p;
            if (where != null)
            {
                result = result.Where(where);
                if (order != null)
                {
                    result = result.OrderBy(order);
                }
                else
                {
                    result = result.OrderBy(m => m.Id);

                }
            }
            rowCount = result.Count();
            return result.Skip((startPage - 1) * pageSize).Take(pageSize);
        }

        public void Save()
        {

            _dbContext.SaveChanges();
        }

        protected static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId(TPrimaryKey id)
        {
            var lambdaParam = Expression.Parameter(typeof(TEntity));
            var lambdaBody = Expression.Equal(
                Expression.PropertyOrField(lambdaParam, "id"),
                Expression.Constant(id, typeof(TPrimaryKey)));
            return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam);
        }
    }

    public abstract class FonourRepositoryBase<TEntity> : FonourRepositoryBase<TEntity, Guid> where TEntity : Entity
    {
        protected FonourRepositoryBase(FonourDbContext dbContext) : base(dbContext)
        {

        }
    }
}
